use std::ops::{Deref, DerefMut};

use windows::Win32::System::IO::OVERLAPPED;

use super::{nodebug::NoDebug, win_handle::WinHandle};




#[repr(transparent)]
pub(super) struct Overlapped(pub(super) OVERLAPPED);

impl Drop for Overlapped {
    fn drop(&mut self) {
        unsafe {
            if !self.0.hEvent.is_invalid() {
                let result = windows::Win32::Foundation::CloseHandle(self.0.hEvent);
                assert!(result.as_bool() || std::thread::panicking());
            }
        }
    }
}

impl Overlapped {
    pub(super) fn new(ov: OVERLAPPED) -> Self {
        Self(ov)
    }
}

impl Deref for Overlapped {
    type Target = OVERLAPPED;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Overlapped {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}


/// Helper struct for all data being aliased by the kernel during async reads.
#[derive(Debug)]
pub(crate) struct AsyncData {
    /// File handle of the pipe on which the async operation is performed.
    pub(super) handle: WinHandle,

    /// Meta-data for this async read operation, filled by the kernel.
    ///
    /// This must be on the heap, in order for its memory location --
    /// which is registered in the kernel during an async read --
    /// to remain stable even when the enclosing structure is passed around.
    pub(super) ov: NoDebug<Box<Overlapped>>,

    /// Buffer for the kernel to store the results of the async read operation.
    ///
    /// The vector provided here needs to have some allocated yet unused space,
    /// i.e. `capacity()` needs to be larger than `len()`.
    /// If part of the vector is already filled, that is left in place;
    /// the new data will only be written to the unused space.
    pub(super) buf: Vec<u8>,
}